package com.aloha.minio.service.impl;

import com.aloha.minio.config.MinioConfig;
import com.aloha.minio.config.MinioConfigProperties;
import com.aloha.minio.entity.MinioResult;
import com.aloha.minio.service.MinioService;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.io.*;
import java.util.concurrent.TimeUnit;

/**
 * @author DaiZhiHeng
 * @description minion服务实现类
 * @date 2023/4/5 14:34
 */
@EnableConfigurationProperties(MinioConfigProperties.class)
@Import(MinioConfig.class)
public class MinioServiceImpl implements MinioService, InitializingBean {

    @Resource
    private MinioClient minioClient;

    @Resource
    private MinioConfigProperties minioConfigProperties;

    private static String bucket;

    @Override
    public MinioResult uploadFile(byte[] data, String objectName) {
        try (ByteArrayInputStream is = new ByteArrayInputStream(data)) {
            PutObjectArgs objectArgs = PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    //-1表示文件分片按5M(不小于5M,不大于5T),分片数量最大10000
                    .stream(is, is.available(), -1)
                    .contentType(getContentType(objectName))
                    .build();
            minioClient.putObject(objectArgs);
            return new MinioResult().build(minioConfigProperties, objectName);
        } catch (Exception e) {
            throw new RuntimeException("file upload failed");
        }
    }

    @Override
    public MinioResult uploadFile(String localFilePath, String objectName) {
        try {
            UploadObjectArgs objectArgs = UploadObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    .filename(localFilePath)
                    .build();
            minioClient.uploadObject(objectArgs);
            return new MinioResult().build(minioConfigProperties, objectName);
        } catch (Exception e) {
            throw new RuntimeException("file upload failed");
        }
    }

    @Override
    public boolean exists(String objectName) {
        GetObjectArgs objectArgs = GetObjectArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .build();
        try (InputStream is = minioClient.getObject(objectArgs)) {
            if (is == null) return false;
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    @Override
    public File download(File target, String objectName) {
        GetObjectArgs objectArgs = GetObjectArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .build();
        try (InputStream is = minioClient.getObject(objectArgs);
             OutputStream os = new FileOutputStream(target)) {
            IOUtils.copy(is, os);
        } catch (Exception e) {
            throw new RuntimeException("file download failed");
        }
        return target;
    }

    @Override
    public boolean delete(String objectName) {
        try {
            RemoveObjectArgs objectArgs = RemoveObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    .build();
            minioClient.removeObject(objectArgs);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    @Override
    public void deleteDir(String dir) {
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
                .bucket(bucket)
                .prefix(dir)
                .build();
        Iterable<Result<Item>> results = minioClient.listObjects(listObjectsArgs);
        // 删除
        results.forEach(o -> {
            try {
                minioClient.removeObject(RemoveObjectArgs.builder()
                        .bucket(bucket)
                        .object(o.get().objectName())
                        .build());
            } catch (Exception e) {
                throw new RuntimeException("dir deleted failed");
            }
        });
    }

    @Override
    public String policy(int expire, TimeUnit unit, String objectName) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucket)
                .object(objectName)
                .expiry(expire, unit)
                .method(Method.PUT).build();
        try {
            return minioClient.getPresignedObjectUrl(args);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("generate policy error");
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        bucket = minioConfigProperties.getBucket();
    }
}
